/**
 * @author：anlzou
 * @Date：Created in0:43 2021/4/13
 * @Github：https://github.com/anlzou
 * @Description：
 */
package com.anlzou.code;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Scanner;
import java.util.stream.Stream;

/**
 * java从文件中读取数据的6种方法
 *
 * 1. Scanner(Java 1.5) 按行读数据及String、Int类型等按分隔符读数据
 * 2. Files.lines, 返回Stream(Java 8) 流式数据处理，按行读取
 * 3. Files.readAllLines, 返回List<String>(Java 8)
 * 4. Files.readString, 读取String(Java 11), 文件最大 2G
 * 5. Files.readAllBytes, 读取byte[](Java 7), 文件最大 2G
 * 6. BufferedReader, 经典方式 (Java 1.1 -> forever)
 */
public class ReadFileData6ways {

    /**
     * 1. Scanner(Java 1.5) 按行读数据及String、Int类型等按分隔符读数据。
     *
     * 提供了：
     * ------------------------
     *   - fileName                         :String
     * ------------------------
     *   + setFileName(String fileName)     :void
     *   + readByLine()                     :void
     *   + readByDelimiter(String delimiter):void
     * ------------------------
     */
    public static class ReadFile_Scanner{
        //默认读取的文件
        private String fileName = "output/newFile01.txt";

        public ReadFile_Scanner(){}

        public ReadFile_Scanner(String fileName){
            this.fileName = fileName;
        }

        public void setFileName(String fileName) {
            this.fileName = fileName;
        }

        public void readByLine() throws IOException {
            try (Scanner sc = new Scanner(new FileReader(fileName))) {
                while (sc.hasNextLine()) {  //按行读取字符串
                    String line = sc.nextLine();
                    System.out.println(line);
                }
            }
        }

        //使用分隔符处理字符串
        public void readByDelimiter(String delimiter) throws IOException {
            try (Scanner sc = new Scanner(new FileReader(fileName))) {
                sc.useDelimiter(delimiter);    //分隔符
                while (sc.hasNext()) {   //按分隔符读取字符串
                    String str = sc.next();
                    System.out.println(str);
                }
            }
        }

        /*//sc.hasNextInt() 、hasNextFloat() 、基础数据类型等等等等。
        fileName = "output/number.txt";
        try (Scanner sc = new Scanner(new FileReader(fileName))) {
            sc.useDelimiter("\\、");     //分隔符
            while (sc.hasNextInt()) {   //按分隔符读取Float，不可以被其它规则打断
                int intValue = sc.nextInt();
                System.out.println(intValue);
            }
        }
        System.out.println("\n\n==============");*/
    }


    /**
     * 2. Files.lines, 返回Stream(Java 8) 流式数据处理，按行读取
     *
     * 提供了：
     * ------------------------
     *   - fileName                         :String
     * ------------------------
     *   + setFileName(String fileName)     :void
     *   + readFile()                       :void
     * ------------------------
     */
    public static class ReadFile_Files_lines{
        private String fileName = "output/defaultFile.txt";

        public ReadFile_Files_lines(){}

        public ReadFile_Files_lines(String fileName){
            this.fileName = fileName;
        }

        public void setFileName(String fileName) {
            this.fileName = fileName;
        }

        /**读取文件函数*/
        public void readFile() throws IOException {
            // 读取文件内容到Stream流中，按行读取
            Stream<String> lines = Files.lines(Paths.get(fileName));
            // 随机行顺序进行数据处理
            lines.forEach(ele->{
                System.out.println(ele);
            });
        }
    }


    /**
     * 3. Files.readAllLines, 返回List<String>(Java 8)
     *
     * 提供了：
     * ------------------------
     *   - fileName                         :String
     * ------------------------
     *   + setFileName(String fileName)     :void
     *   + readFile()                       :void
     * ------------------------
     */
    public static class ReadFile_Files_readAllLines{
        private String fileName = "output/defaultFile.txt";

        public ReadFile_Files_readAllLines(){}

        public ReadFile_Files_readAllLines(String fileName){
            this.fileName = fileName;
        }

        public void setFileName(String fileName) {
            this.fileName = fileName;
        }

        public void readFile() throws IOException {
            // 转换成List<String>, 要注意java.lang.OutOfMemoryError: Java heap space
            List<String> lines = Files.readAllLines(Paths.get(fileName),
                    StandardCharsets.UTF_8);
            lines.forEach(System.out::println);
        }
    }


    /**
     * 4. Files.readString, 读取String(Java 11), 文件最大 2G
     *
     * 提供了：
     * ------------------------
     *   - fileName                         :String
     * ------------------------
     *   + setFileName(String fileName)     :void
     *   + readFile()                       :void
     * ------------------------
     */
    public static class ReadFile_Files_String{
        private String fileName = "output/defaultFile.txt";

        public ReadFile_Files_String(){}

        public ReadFile_Files_String(String fileName){
            this.fileName = fileName;
        }

        public void setFileName(String fileName) {
            this.fileName = fileName;
        }

        public void readFile() throws IOException {
            // java 11 开始提供的方法，读取文件不能超过2G，与你的内存息息相关
            String string = Files.readString(Paths.get(fileName));
            System.out.println(string);
        }
    }


    /**
     * 5. Files.readAllBytes, 读取byte[](Java 7), 文件最大 2G
     *
     * 提供了：
     * ------------------------
     *   - fileName                         :String
     * ------------------------
     *   + setFileName(String fileName)     :void
     *   + readFile()                       :void
     * ------------------------
     */
    public static class ReadFile_Files_readAllBytes{
        private String fileName = "output/defaultFile.txt";

        public ReadFile_Files_readAllBytes(){}

        public ReadFile_Files_readAllBytes(String fileName){
            this.fileName = fileName;
        }

        public void setFileName(String fileName) {
            this.fileName = fileName;
        }

        public void readFile() throws IOException {
            //如果是JDK11用上面的方法，如果不是用这个方法也很容易
            byte[] bytes = Files.readAllBytes(Paths.get(fileName));

            //先将数据读取为二进制数组，然后转换成String内容
            String content = new String(bytes, StandardCharsets.UTF_8);
            System.out.println(content);
        }
    }


    /**
     * 6. BufferedReader, 经典方式 (Java 1.1 -> forever)
     *
     * 提供了：
     * ------------------------
     *   - fileName                         :String
     * ------------------------
     *   + setFileName(String fileName)     :void
     *   + readFileBufferReder()            :void
     *   + readFileFnBufferReder            :void
     * ------------------------
     */
    public static class ReadFile_BufferedReader{
        private String fileName = "output/defaultFile.txt";

        public ReadFile_BufferedReader(){}

        public ReadFile_BufferedReader(String fileName){
            this.fileName = fileName;
        }

        public void setFileName(String fileName) {
            this.fileName = fileName;
        }

        public void readFileBufferReder() throws IOException {
            // 带缓冲的流读取，默认缓冲区8k
            try (BufferedReader br = new BufferedReader(new FileReader(fileName))){
                String line;
                while ((line = br.readLine()) != null) {
                    System.out.println(line);
                }
            }
        }

        public void readFileFnBufferReder() throws IOException {
            //java 8中这样写也可以
            try (BufferedReader br = Files.newBufferedReader(Paths.get(fileName))){
                String line;
                while ((line = br.readLine()) != null) {
                    System.out.println(line);
                }
            }
        }
    }

}
